// 路由权限守卫
// src/router/permission.ts
import type {
  Router,
  RouteLocationNormalized,
  NavigationGuardNext,
} from 'vue-router';
import { constantRoutes, dynamicRoutes } from '@/router/routes'; // 假设路由定义在 routes.ts
import { useUserStore } from '@/store/modules/user.ts';
import { getToken } from '@/common/utils/cache/cookies';
import router from '@/router';

// 白名单：不需要权限也可以访问的路由
const whiteList = ['/login', '/404', '/403'];

// 用于标记不同级别的路由是否已添加
const routeAddedFlag = {
  system: false,
  project: {} as Record<string, boolean>, // key: projectId, value: boolean
};

// 清空路由添加标志的函数
export function clearRouteAddedFlags() {
  routeAddedFlag.system = false;
  Object.keys(routeAddedFlag.project).forEach((key) => {
    delete routeAddedFlag.project[key];
  });
}

/**
 * @name 重置动态路由
 * @description 移除所有动态添加的路由，并将路由状态标志重置为初始状态
 *              通常在用户退出登录时调用。
 */
export function resetRouter() {
  // 获取所有路由的 name
  const allRouteNames = router.getRoutes().map((route) => route.name);

  // 获取所有常驻路由的 name
  const constantRouteNames = new Set(constantRoutes.map((route) => route.name));

  // 遍历所有路由，如果该路由不在常驻路由中，则移除它
  allRouteNames.forEach((name) => {
    if (name && !constantRouteNames.has(name as string)) {
      router.removeRoute(name as string);
    }
  });
}

// 检查路径是否存在
function checkPathExists(path: string): boolean {
  // 检查常驻路由
  for (const route of constantRoutes) {
    if (route.path === path) {
      return true;
    }
  }

  // 检查动态路由
  function findRouteByPath(
    targetPath: string,
    routes: any[],
    parentPath: string = ''
  ): boolean {
    for (const route of routes) {
      // 构建完整路径
      let fullPath = route.path;
      if (parentPath) {
        // 如果父路径以 / 结尾，子路径不以 / 开头，则直接拼接
        if (parentPath.endsWith('/') && !route.path.startsWith('/')) {
          fullPath = parentPath + route.path;
        } else if (!parentPath.endsWith('/') && !route.path.startsWith('/')) {
          fullPath = parentPath + '/' + route.path;
        } else {
          fullPath = parentPath + route.path;
        }
      }

      // 精确匹配
      if (fullPath === targetPath) {
        return true;
      }

      // 动态路由匹配
      if (fullPath.includes(':')) {
        // 将动态路由转换为正则表达式
        let pattern = fullPath.replace(/:\w+/g, '\\d+');
        pattern = '^' + pattern + '$';

        const regex = new RegExp(pattern);
        if (regex.test(targetPath)) {
          return true;
        }
      }

      // 检查子路由
      if (route.children) {
        if (findRouteByPath(targetPath, route.children, fullPath)) {
          return true;
        }
      }
    }
    return false;
  }

  return findRouteByPath(path, dynamicRoutes);
}

// 检查用户是否有权限访问特定路径
function checkPathPermission(
  path: string,
  userStore: any,
  projectId?: number
): boolean {
  // 查找匹配的路由配置
  function findRouteByPath(targetPath: string, routes: any[]): any {
    for (const route of routes) {
      // 精确匹配
      if (route.path === targetPath) {
        return route;
      }

      // 动态路由匹配
      if (route.path.includes(':')) {
        const routePattern = route.path.replace(/:\w+/g, '\\d+');
        const regex = new RegExp(`^${routePattern}$`);
        if (regex.test(targetPath)) {
          return route;
        }
      }

      // 检查子路由
      if (route.children) {
        const childRoute = findRouteByPath(targetPath, route.children);
        if (childRoute) {
          return childRoute;
        }
      }
    }
    return null;
  }

  const routeConfig = findRouteByPath(path, dynamicRoutes);

  // 如果没有找到路由配置，或者路由没有设置权限要求，则允许访问
  if (!routeConfig || !routeConfig.meta?.permission) {
    return true;
  }

  // 检查用户是否有相应权限
  return userStore.hasPermission(
    routeConfig.meta.permission,
    routeConfig.meta.level || 'system',
    false,
    projectId
  );
}

// 导出一个函数，用于初始化权限守卫
export function setupPermissionGuard(router: Router) {
  router.beforeEach(
    async (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized,
      next: NavigationGuardNext
    ) => {
      const userStore = useUserStore();

      // 在路由守卫开始处添加
      /**
       * 递归过滤异步路由表
       * @param routes 所有待过滤的路由
       * @param type 权限类型
       * @param projectId 项目ID（用于项目级权限检查）
       */
      function filterAsyncRoutes(
        routes: any[],
        type?: string,
        projectId?: number
      ) {
        const res: any[] = [];

        routes.forEach((route) => {
          const tmp = { ...route };

          // 如果路由没有设置permission，或者用户权限包含了路由所需的任意一个权限
          const hasRequiredPermission =
            !tmp.meta?.permission ||
            userStore.hasPermission(
              tmp.meta.permission,
              type,
              false,
              projectId
            );

          if (hasRequiredPermission) {
            if (tmp.children) {
              tmp.children = filterAsyncRoutes(tmp.children, type, projectId);

              // 特殊处理：admin-panel 路由的智能重定向
              if (tmp.name === 'admin-panel' && tmp.children.length > 0) {
                // 找到第一个有权限的子路由
                const firstAvailableChild = tmp.children[0];
                if (firstAvailableChild) {
                  tmp.redirect = (to: any) => ({
                    path: `${to.path}/${firstAvailableChild.path}`,
                  });
                }
              }
            }
            res.push(tmp);
          }
        });

        return res;
      }

      const hasToken = getToken();

      // 1. 已登录
      if (hasToken) {
        // 确保用户信息已加载（无论访问什么路由）
        if (!userStore.userInfo) {
          await userStore.getCurrentUserInfo();
        }

        if (to.path === '/login') {
          next({ path: '/' });
        } else {
          // 首先检查路径是否存在
          if (!checkPathExists(to.path)) {
            next('/404');
            return;
          }

          // 检查是否是动态路由路径
          const isSystemRoute = to.path === '/' || to.path === '/home';
          const isProjectRoute = to.path.startsWith('/project/');

          // 情况A：访问系统级路由
          if (isSystemRoute) {
            if (!routeAddedFlag.system) {
              // 1. 获取用户信息和系统级权限
              if (!userStore.userInfo) {
                await userStore.getCurrentUserInfo();
              }
              // 2. 过滤出用户有权访问的系统级路由
              const filteredSystemRoutes = filterAsyncRoutes(
                dynamicRoutes,
                'system'
              );

              // 3. 动态添加到路由实例中
              filteredSystemRoutes.forEach((route) => {
                router.addRoute(route);
              });

              routeAddedFlag.system = true;

              // 4. 重新进入当前路由，因为新添加的路由需要时间生效
              next({ ...to, replace: true });
              return; // 重要：添加后立即返回，避免后续逻辑干扰
            }

            // 每次访问都检查权限
            if (!checkPathPermission(to.path, userStore)) {
              next('/403');
              return;
            }
            next(); // 系统路由已添加，直接放行
          }
          // 情况B：访问项目级路由
          else if (isProjectRoute) {
            const projectIdMatch = to.path.match(/^\/project\/(\d+)/);
            const projectId = projectIdMatch ? Number(projectIdMatch[1]) : null;
            if (!userStore.userInfo) {
              await userStore.getCurrentUserInfo();
            }
            if (!projectId) {
              next('/404'); // 没有有效的 projectId，是无效路由
              return;
            }

            if (!routeAddedFlag.project[projectId]) {
              // 1. 加载该项目的权限
              await userStore.getProjectPermissions(projectId);

              // 3. 过滤出用户在该项目下有权访问的路由
              const filteredProjectRoutes = filterAsyncRoutes(
                dynamicRoutes,
                'project',
                projectId
              );

              // 4. 动态添加到路由实例中
              filteredProjectRoutes.forEach((route) => {
                // 注意：addRoute 会处理 path 中的参数，如 /project/:projectId
                router.addRoute(route);
              });

              routeAddedFlag.project[projectId] = true;
              // 5. 重新进入当前路由
              next({ ...to, replace: true });
              return;
            }

            // 每次访问都检查权限
            if (!checkPathPermission(to.path, userStore, projectId)) {
              next('/403');
              return;
            }
            next(); // 该项目路由已添加，直接放行
          }
          // 情况C：访问其他已注册的路由（比如首页），或者路由已添加
          // 这里是关键修改点！
          // 我们需要判断，当前这次导航是不是由我们自己的守卫发起的"重新进入"
          // 一个简单的判断方法是，如果 to 和 from 是同一个路径，那很可能就是一次"重新进入"
          // 在这种情况下，我们也应该使用 replace 来避免创建新的历史记录
          if (to.path === from.path) {
            // 如果是守卫自己重定向回来的，使用 replace 模式放行
            next({ ...to, replace: true });
          } else {
            // 否则，是正常的页面间跳转，正常放行
            next();
          }
        }
      } else {
        // 未登录逻辑...
        if (whiteList.includes(to.path)) {
          next();
        } else {
          next(`/login?redirect=${to.path}`);
        }
      }
    }
  );
}
